#pragma once

// Possible solvers
#define PL_SOLVER_IML 0
#define PL_SOLVER_OPENCV 1

// Used solver
#define PL_LINEAR_EQUATION_SYSTEM_SOLVER PL_SOLVER_IML

#if PL_LINEAR_EQUATION_SYSTEM_SOLVER == PL_SOLVER_IML
	#include "comprow_double.h"              // Compressed column matrix header
	#include "mvblasd.h"                     // MV_Vector level 1 BLAS
#endif

#if PL_LINEAR_EQUATION_SYSTEM_SOLVER == PL_SOLVER_OPENCV
	#include "opencv2\opencv.hpp"
#endif

#include "PLDataTypes.h"
#include "PLMatrixOperations.h"

#include <map>
#include <vector>

/**
  *	A linear equation system of the form A * x = b. A is an mxn matrix, x is
  * the solution vector of the form nx1. b is a mx1 vector.
  */
class PLLinearEquationSystem
{
public:
	PLLinearEquationSystem( const PLuint &numRows, const PLuint &numCols );
	~PLLinearEquationSystem( void );

	void FillA( const std::vector<PLuint> &variables,
		const std::vector<double> &coefficients,
		const double &weight, const double &f );
	void Finalize( void );

	const PLuint &GetNumRows( void ) const;
	const PLuint &GetNumCols( void ) const;

	void Reset( void );
	void Solve( void );

	const double &X( const PLuint index ) const;

private:

	PLuint mNumRows;
	PLuint mNumCols;

	void Initialize( void );

#if PL_LINEAR_EQUATION_SYSTEM_SOLVER == PL_SOLVER_IML
	/** map, that maps matrix coordinates to the corresponding double value */
	std::map<PLMatrixCoordinate, double, PLMatrixCoordinate::PLMatrixCoordinateCompare> mMatrixCoordinateToValueMap;
	/** map, that maps vector indexes to the corresponding double value */
	std::map<PLuint, double> mVectorIndexToValueMap;

	/** matrix A in the equation A * x = b */
	CompRow_Mat_double *mMatrixA;
	/** vector b in the equation A * x = b */
	VECTOR_double *mVectorB;
	/** vector x in the equation A * x = b */
	VECTOR_double *mVectorX;
#endif

#if PL_LINEAR_EQUATION_SYSTEM_SOLVER == PL_SOLVER_OPENCV
	/** matrix A in the equation A * x = b */
	CvMat *mMatrixA;
	/** vector b in the equation A * x = b */
	CvMat *mVectorB;
	/** vector x in the equation A * x = b */
	CvMat *mVectorX;
#endif

};